import { describe, it, expect, beforeEach } from 'vitest';
import { createPinia, setActivePinia } from 'pinia';
import { useRestorationStore } from '../../src/stores/restorationStore';
import imageRestorationService from '../../src/services/ImageRestorationService';
import imageStitchingService from '../../src/services/ImageStitchingService';
import { generateTestImages } from './utils/imageGenerator';
import { measurePerformance, logPerformanceResult, runPerformanceTest } from './utils/performanceUtils';
import type { UploadedImage, StitchingOptions, ImageMetadata } from '../../src/types/models';

// Helper function to convert File objects to UploadedImage objects
async function filesToUploadedImages(files: File[]): Promise<UploadedImage[]> {
  return files.map((file, index) => {
    // Extract dimensions from filename
    const match = file.name.match(/(\d+)x(\d+)/);
    const width = match ? parseInt(match[1]) : 800;
    const height = match ? parseInt(match[2]) : 600;
    
    return {
      id: `test-${index}`,
      file,
      url: URL.createObjectURL(file),
      name: file.name,
      width,
      height,
      fileSize: file.size,
      format: file.name.endsWith('.png') ? 'png' : 'jpg'
    };
  });
}

// Helper function to create a stitched image and metadata for testing
async function createStitchedImageAndMetadata(
  imageCount: number,
  width: number = 800,
  height: number = 600
): Promise<{ stitchedImageFile: File; metadata: ImageMetadata }> {
  // Generate test images
  const files = await generateTestImages(imageCount, width, width, height, height);
  const images = await filesToUploadedImages(files);
  
  // Define stitching options
  const options: StitchingOptions = {
    arrangement: 'grid',
    spacing: 0,
    maxWidth: 12000,
    maxHeight: 12000,
    backgroundColor: '#ffffff'
  };
  
  // Stitch images
  const stitchedImage = await imageStitchingService.stitchImages(images, options);
  
  // Generate metadata
  const metadata = imageStitchingService.generateMetadata(images, stitchedImage, options);
  
  // Convert stitched image canvas to file
  const stitchedImageFile = await new Promise<File>((resolve, reject) => {
    stitchedImage.canvas.toBlob((blob) => {
      if (blob) {
        resolve(new File([blob], 'stitched-image.png', { type: 'image/png' }));
      } else {
        reject(new Error('Failed to convert canvas to blob'));
      }
    }, 'image/png');
  });
  
  return { stitchedImageFile, metadata };
}

describe('Image Restoration Performance', () => {
  beforeEach(() => {
    // Create a fresh Pinia instance for each test
    setActivePinia(createPinia());
  });
  
  it('should measure restoration performance with different image counts', async () => {
    // Test with different numbers of images
    const imageCounts = [4, 9, 16];
    
    for (const count of imageCounts) {
      // Create stitched image and metadata
      const { stitchedImageFile, metadata } = await createStitchedImageAndMetadata(count);
      
      // Calculate total pixels
      const totalPixels = metadata.images.reduce(
        (sum, image) => sum + image.width * image.height,
        0
      );
      
      // Measure performance
      const { performance } = await measurePerformance(
        `Restore ${count} images`,
        async () => {
          return await imageRestorationService.restoreImages(stitchedImageFile, metadata);
        },
        {
          imageCount: count,
          totalPixels,
          stitchedImageSize: `${metadata.stitchedImageSize.width}x${metadata.stitchedImageSize.height}`
        }
      );
      
      // Log performance result
      logPerformanceResult(performance);
      
      // Verify that the restoration was successful
      expect(performance.duration).toBeGreaterThan(0);
    }
  });
  
  it('should measure restoration performance with different image sizes', async () => {
    // Test with different image sizes
    const imageSizes: Array<[number, number]> = [
      [800, 600],    // Small: 0.48 MP
      [1600, 1200],  // Medium: 1.92 MP
      [3200, 2400]   // Large: 7.68 MP
    ];
    
    for (const [width, height] of imageSizes) {
      // Create stitched image and metadata
      const { stitchedImageFile, metadata } = await createStitchedImageAndMetadata(4, width, height);
      
      // Calculate total pixels
      const totalPixels = metadata.images.reduce(
        (sum, image) => sum + image.width * image.height,
        0
      );
      
      // Measure performance
      const { performance } = await measurePerformance(
        `Restore 4 images of size ${width}x${height} (${(width * height / 1000000).toFixed(2)} MP each)`,
        async () => {
          return await imageRestorationService.restoreImages(stitchedImageFile, metadata);
        },
        {
          imageCount: 4,
          totalPixels,
          imageSize: `${width}x${height}`,
          megapixelsPerImage: (width * height / 1000000).toFixed(2),
          stitchedImageSize: `${metadata.stitchedImageSize.width}x${metadata.stitchedImageSize.height}`
        }
      );
      
      // Log performance result
      logPerformanceResult(performance);
      
      // Verify that the restoration was successful
      expect(performance.duration).toBeGreaterThan(0);
    }
  });
  
  it('should measure metadata validation performance', async () => {
    // Create stitched image and metadata
    const { stitchedImageFile, metadata } = await createStitchedImageAndMetadata(9);
    
    // Measure performance
    const { performance } = await measurePerformance(
      'Validate metadata',
      async () => {
        return await imageRestorationService.validateMetadata(stitchedImageFile, metadata);
      },
      {
        imageCount: metadata.images.length,
        stitchedImageSize: `${metadata.stitchedImageSize.width}x${metadata.stitchedImageSize.height}`
      }
    );
    
    // Log performance result
    logPerformanceResult(performance);
    
    // Verify that the validation was successful
    expect(performance.duration).toBeGreaterThan(0);
  });
  
  it('should measure restoration store performance', async () => {
    // Get restoration store
    const restorationStore = useRestorationStore();
    
    // Create stitched image and metadata
    const { stitchedImageFile, metadata } = await createStitchedImageAndMetadata(9);
    
    // Set stitched image file and metadata
    restorationStore.stitchedImageFile = stitchedImageFile;
    restorationStore.metadata = metadata;
    
    // Validate metadata
    const validationResult = await imageRestorationService.validateMetadata(stitchedImageFile, metadata);
    restorationStore.validationResult = validationResult;
    
    // Calculate total pixels
    const totalPixels = metadata.images.reduce(
      (sum, image) => sum + image.width * image.height,
      0
    );
    
    // Measure performance
    const { performance } = await measurePerformance(
      'Restoration store restoreImages',
      async () => {
        return await restorationStore.restoreImages();
      },
      {
        imageCount: metadata.images.length,
        totalPixels,
        stitchedImageSize: `${metadata.stitchedImageSize.width}x${metadata.stitchedImageSize.height}`
      }
    );
    
    // Log performance result
    logPerformanceResult(performance);
    
    // Verify that the restoration was successful
    expect(performance.duration).toBeGreaterThan(0);
    expect(restorationStore.restoredImages.length).toBe(metadata.images.length);
  });
});